package com.yunxin.download.server.infra.support.file.export.service;


import com.yunxin.common.exception.BusinessException;
import com.yunxin.common.result.ResultCode;
import com.yunxin.download.server.infra.constant.enums.FileTypeEnum;
import com.yunxin.download.server.infra.support.file.FileHeader;
import com.yunxin.download.server.infra.support.file.FileHeaderItem;
import com.yunxin.download.server.infra.utils.FileHeaderUtils;
import com.yunxin.download.server.infra.utils.ReflectUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

/**
 * csv文件导出
 * 目前使用阿里的tool 基于poi的 跑在内存里面 XSSF  后续可以改成SXSSF  低内存生成方式
 * @author zero°
 * @since 2023-06-15
 */
@Slf4j
public class CsvFileExportServiceImpl implements FileExportService {

    private CSVPrinter csvPrinter;
    private OutputStream outputStream;
    List<FileHeaderItem> fileHeaderItems;
    private List<String> propNames;


    @Override
    public void init(String sheetName, Class<? extends FileHeader> excelHeaderClass, OutputStream outputStream) {
        // 写入bom, 防止中文乱码
        byte[] bytes = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
        try {
            fileHeaderItems = FileHeaderUtils.X.getFilelHeader(excelHeaderClass);
            outputStream.write(bytes);

            String[] headers = new String[fileHeaderItems.size()];
            propNames = fileHeaderItems.stream().map(FileHeaderItem::getPropName).collect(Collectors.toList());

            for (int i = 0; i < fileHeaderItems.size(); i++) {
                headers[i] = fileHeaderItems.get(i).getExcelColumnName();
            }

            OutputStreamWriter osw = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
            CSVFormat csvFormat = CSVFormat.EXCEL.withHeader(headers);

            csvPrinter = new CSVPrinter(osw, csvFormat);
            this.outputStream = outputStream;
        } catch (IOException e) {
            log.error("初始化失败", e);
            throw new BusinessException(ResultCode.SYSTEM_EXECUTION_ERROR);
        }
    }


    @SneakyThrows
    @Override
    public void append(List<Object> data) {
        for (Object value : data) {
            List<Object> fieldValues = ReflectUtil.X.getFieldValues(value, propNames);
            for (Object fieldValue : fieldValues) {
                csvPrinter.print(fieldValue);
            }
            csvPrinter.println();
        }
    }

    @SneakyThrows
    @Override
    public OutputStream finish() {
        csvPrinter.flush();
        csvPrinter.close();
        return this.outputStream;
    }

    @Override
    public String getFileTypeSuffix() {
        return FileTypeEnum.CSV.getType();
    }
}
